﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using Common.Utilities;
using Common.Utilities.Dispatcher;

namespace Workflows.Components.Entities.MasterData
{
    /// <summary>
    /// 
    /// </summary>
    [Serializable]
    public class DbProfileInstruction:InstructionBase
    {
        #region props
        private string _DataSourceName;
        /// <summary></summary>
        public string DataSourceName
        {
            get
            {
                return this._DataSourceName;
            }
            set
            {
                this._DataSourceName = value;
            }
        }

        private string _DbName;
        /// <summary></summary>
        public string DbName
        {
            get
            {
                return this._DbName;
            }
            set
            {
                this._DbName = value;
            }
        }

        private bool _IntegratedSecurity;
        /// <summary></summary>
        public bool IntegratedSecurity
        {
            get
            {
                return this._IntegratedSecurity;
            }
            set
            {
                this._IntegratedSecurity = value;
            }
        }

        private string _DbUserName;
        /// <summary></summary>
        public string DbUserName
        {
            get
            {
                return this._DbUserName;
            }
            set
            {
                this._DbUserName = value;
            }
        }

        private string _DbPassword;
        /// <summary></summary>
        public string DbPassword
        {
            get
            {
                return this._DbPassword;
            }
            set
            {
                this._DbPassword = value;
            }
        }

        private Dictionary<string,List<string>> _TablesBySchemas;
        /// <summary></summary>
        public Dictionary<string,List<string>> TablesBySchemas
        {
            get
            {
                return this._TablesBySchemas;
            }
            set
            {
                this._TablesBySchemas = value;
            }
        }

        private bool _ProfileIndexedColumnsOnly;
        /// <summary></summary>
        public bool ProfileIndexedColumnsOnly
        {
            get
            {
                return this._ProfileIndexedColumnsOnly;
            }
            set
            {
                this._ProfileIndexedColumnsOnly = value;
            }
        }

        private string _OutputFilePath;
        /// <summary></summary>
        public string OutputFilePath
        {
            get
            {
                return this._OutputFilePath;
            }
            set
            {
                this._OutputFilePath = value;
            }
        }
        #endregion

        #region ctor
        public DbProfileInstruction():base(Guid.Empty, Guid.Empty)
        {
            this._DataSourceName = string.Empty;
            this._DbName = string.Empty;
            this._IntegratedSecurity = true;
            this._DbUserName = string.Empty;
            this._DbPassword = string.Empty;
            this._TablesBySchemas=new Dictionary<string, List<string>>();
            this._ProfileIndexedColumnsOnly = false;
            this._OutputFilePath = string.Empty;
        }

        public DbProfileInstruction(
            Guid componentID, Guid jobTicketID,
            string dataSrc, string dbName, 
            Dictionary<string,List<string>> tbls,
            bool integratedSecurity, string userID, string pwd,
            bool indexedColumnsOnly,
            string outputFilePath)
            : base(componentID, jobTicketID)
        {
            this._DataSourceName = dataSrc;
            this._DbName = dbName;
            this._IntegratedSecurity = integratedSecurity;
            this._DbUserName = userID;
            this._DbPassword = pwd;
            this._TablesBySchemas = tbls;
            this._ProfileIndexedColumnsOnly = indexedColumnsOnly;
            this._OutputFilePath = outputFilePath;
        }

        #endregion

        public override XmlNode Serialize(ref XmlDocument xDoc, ref XmlNode parentNode)
        {
            XmlNode xNode = XmlDataUtil.AddElement(ref xDoc, parentNode, "Instruction");
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "Type", this.GetType().FullName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ComponentID", this.OwnerComponentID.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "WorkerID", this.OwnerWorkerInstanceID.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SubmitTime", this.SubmitTime.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "StartTime", this.StartTime.ToString());

            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "DataSource", this.DataSourceName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "DbName", this.DbName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "IntegratedSecurity", this.IntegratedSecurity.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "UserID", this.DbUserName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "Password", this.DbPassword);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ProfileIndexedColumnsOnly",this.ProfileIndexedColumnsOnly.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "OutputFilePath", this.OutputFilePath);
            XmlNode tblNodes = XmlDataUtil.AddElement(ref xDoc, xNode, "Tables");
            if(this.TablesBySchemas !=null && this.TablesBySchemas.Count>0)
            {
                foreach(string schemaName in this.TablesBySchemas.Keys)
                {
                    foreach(string tblName in this.TablesBySchemas[schemaName])
                    {
                        XmlNode tblNode = XmlDataUtil.AddElement(ref xDoc, tblNodes, "Table");
                        XmlDataUtil.UpdateAttribute(ref xDoc, tblNode,"SchemaName",schemaName);
                        XmlDataUtil.UpdateAttribute(ref xDoc, tblNode, "TableName", tblName);
                    }
                }
            }
            
            return xNode;
        }

        public override InstructionBase Instantiate(XmlNode xNode)
        {
            if (xNode.Attributes.GetNamedItem("Type").Value == this.GetType().FullName)
            {
                DbProfileInstruction instruction = new DbProfileInstruction();
                instruction.OwnerComponentID = new Guid(xNode.Attributes.GetNamedItem("ComponentID").Value);
                instruction.OwnerWorkerInstanceID = new Guid(xNode.Attributes.GetNamedItem("WorkerID").Value);
                instruction.SubmitTime = DateTime.Parse(xNode.Attributes.GetNamedItem("SubmitTime").Value);
                instruction.StartTime = DateTime.Parse(xNode.Attributes.GetNamedItem("StartTime").Value);

                instruction.DataSourceName = XmlDataUtil.GetAttributeValue(xNode, "DataSource", "");
                instruction.DbName = XmlDataUtil.GetAttributeValue(xNode, "DbName", "");
                instruction.IntegratedSecurity =
                    bool.Parse(XmlDataUtil.GetAttributeValue(xNode, "IntegratedSecurity", true.ToString()));
                instruction.DbUserName = XmlDataUtil.GetAttributeValue(xNode, "UserID", "");
                instruction.DbPassword = XmlDataUtil.GetAttributeValue(xNode, "Password", "");
                instruction.ProfileIndexedColumnsOnly = bool.Parse(
                    XmlDataUtil.GetAttributeValue(xNode, "ProfileIndexedColumnsOnly", false.ToString()));
                instruction.TablesBySchemas=new Dictionary<string, List<string>>();
                XmlNodeList tblNodes = xNode.SelectNodes("Tables/Table");
                if(tblNodes !=null && tblNodes.Count>0)
                {
                    foreach(XmlNode tblNode in tblNodes)
                    {
                        string schemaName = XmlDataUtil.GetAttributeValue(tblNode, "SchemaName", "dbo");
                        string tblName = XmlDataUtil.GetAttributeValue(tblNode, "TableName", "");
                        List<string> tblNames=new List<string>();
                        if(instruction.TablesBySchemas.ContainsKey(schemaName))
                        {
                            tblNames = instruction.TablesBySchemas[schemaName];
                            tblNames.Add(tblName);
                            instruction.TablesBySchemas[schemaName] = tblNames;
                        }
                        else
                        {
                            tblNames.Add(tblName);
                            instruction.TablesBySchemas.Add(schemaName, tblNames);
                        }
                    }
                }
                instruction.OutputFilePath = XmlDataUtil.GetAttributeValue(xNode, "OutputFilePath", "");

                return instruction;
            }
            else
            {
                throw new Exception("Unable to instantiate instruction: invalid type specified in xml node");
            }
        }
    }
}
